package com.ndood.authenticate.browser;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
import org.springframework.security.web.session.InvalidSessionStrategy;
import org.springframework.security.web.session.SessionInformationExpiredStrategy;
import org.springframework.social.security.SpringSocialConfigurer;

import com.ndood.core.authentication.form.FormAuthenticationConfig;
import com.ndood.core.authentication.mobile.SmsCodeAuthenticationSecurityConfig;
import com.ndood.core.authorize.AuthorizeConfigManager;
import com.ndood.core.properties.SecurityProperties;
import com.ndood.core.validate.code.ValidateCodeSecurityConfig;

/**
 * 浏览器环境下安全配置主类
 * @author ndood
 */
@Configuration
// 激活权限注解
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class BrowserSecurityConfig extends WebSecurityConfigurerAdapter {
	
	@Autowired
	private SecurityProperties securityProperties;
	
	@Autowired
	private PersistentTokenRepository persistentTokenRepository;
	
	@Autowired
	private UserDetailsService userDetailsService;
	
	@Autowired
	private SmsCodeAuthenticationSecurityConfig smsCodeAuthenticationSecurityConfig;
	
	@Autowired
	private ValidateCodeSecurityConfig validateCodeSecurityConfig;
	
	@Autowired
	private FormAuthenticationConfig formAuthenticationConfig;
	
	@Autowired
	private SpringSocialConfigurer springSocialSecurityConfig;
	
	@Autowired
	private InvalidSessionStrategy invalidSessionStrategy;
	
	@Autowired
	private SessionInformationExpiredStrategy sessionInformationExpiredStrategy;
	
	@Autowired
	private LogoutSuccessHandler logoutSuccessHandler;
	
	@Autowired
	private AuthorizeConfigManager authorizeConfigManager;
	
	/**
	 * 添加http安全配置
	 */
	@Override
	protected void configure(HttpSecurity http) throws Exception {
		
		// 自定义表单登录 form不能用apply，否则会报错
		formAuthenticationConfig.configure(http);
		
		http
			// 通用验证码过滤器配置 
			.apply(validateCodeSecurityConfig)
				.and()
			// 自定义短信验证码登录
			.apply(smsCodeAuthenticationSecurityConfig)
				.and()
				
			// 应用social配置，作用是过滤器链上添加一个社交过滤器，当用户访问时引导用户登录
			.apply(springSocialSecurityConfig)
				.and()

			// 配置rememberMe
			.rememberMe()
				.tokenRepository(persistentTokenRepository)
				.tokenValiditySeconds(securityProperties.getBrowser().getRememberMeSeconds())
				.userDetailsService(userDetailsService)
				.and()
				
			// 配置退出登录
			.logout()
				.logoutUrl("/signOut")
				.logoutSuccessHandler(logoutSuccessHandler)
				.deleteCookies("JSESSIONID")
				.and()	
				
			// 配置session管理器，针对session失效返回特定的失败json
			.sessionManagement()
				.invalidSessionStrategy(invalidSessionStrategy)
				.maximumSessions(securityProperties.getBrowser().getSession().getMaximumSessions())
				.maxSessionsPreventsLogin(securityProperties.getBrowser().getSession().isMaxSessionsPreventsLogin())
				.expiredSessionStrategy(sessionInformationExpiredStrategy)
				.and()
				.and()
				
			// 关闭csrf防护
			.csrf() 
				.disable()
			
			// 支持iframe
			.headers().frameOptions().sameOrigin();
		
		// 调用公共的权限管理配置
		authorizeConfigManager.config(http.authorizeRequests());
	}
	
	/**
	 * Unsatisfied dependency expressed through field 'authenticationManager';
	 * https://blog.csdn.net/dandandeshangni/article/details/80145378
	 */
	@Bean
    public AuthenticationManager authenticationManagerBean() throws Exception {
        AuthenticationManager manager = super.authenticationManagerBean();
        return manager;
    }
}
